<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="robot" content="index,follow">
<title>Module fsm - Finite State Machine - Forth Foundation Library</title>
</head>
<body>
<h2>fsm - Finite State Machine</h2>
<h3>Module Description</h3>
<p>The fsm module implements a Finite State Machine. Use fsm-new-state to add
states to the machine. Then use fsm-new-transition to add transitions
between the states. fsm-new-transition returns the new transition. Use
ftr-condition@ on this new transition to get a reference to the condition
in the transition. This is actually a bit array, see [bar]. Use the words
of the bar module to set the condition. When the whole FSM is built, start
using the machine by calling fsm-start. By default the first created
state is the start state, but this can be changed by fsm-start! After
starting the machine, feed events to the machine by fsm-feed. This word
returns the new, current state or nil if no transition matched. The
machine can be converted to graphviz's dot files by fsm-to-dot. This word
uses the labels of the states and transitions to build the dot
representation. It also set the shape of the states (double circle for
start and end states, circles for the others). Use fst-attributes! and
ftr-attributes! to set additional graphviz attributes.
During the feeding of events, the optional actions are called. When a
state is left, the exit action is called, when a state is entered the
entry state is called. If a transition matched, the action of this
transition is also called. The stack usage for those actions:
<pre>
state entry action:  fst -- = State fst is entered
state exit action:   fst -- = State fst is left
transition action: n ftr -- = Transition fst matched for event n
</pre>
</p>
<h3>Module Words</h3>
<dl>
</dl>
<h4>fsm structure</h4>
<dl>
<dt><a name="word1"><b>fsm%</b>	( -- n )</dt>
<dd>Get the required space for a fsm variable</dd>
</dl>
<h4>FSM creation, initialisation and destruction</h4>
<dl>
<dt><a name="word2"><b>fsm-init</b>	( +n fsm -- )</dt>
<dd>Initialise the fsm with the number of events n</dd>
<dt><a name="word3"><b>fsm-(free)</b>	( fsm -- )</dt>
<dd>Free the internal, private variables from the heap</dd>
<dt><a name="word4"><b>fsm-create</b>	( "&lt;spaces&gt;name" +n -- ; -- fsm )</dt>
<dd>Create a named fsm in the dictionary with the number of events n</dd>
<dt><a name="word5"><b>fsm-new</b>	( +n -- fsm )</dt>
<dd>Create a new fsm on the heap with the number of events n</dd>
<dt><a name="word6"><b>fsm-free</b>	( fsm -- )</dt>
<dd>Free the fsm from the heap</dd>
</dl>
<h4>Member words</h4>
<dl>
<dt><a name="word7"><b>fsm-start@</b>	( fsm -- fst )</dt>
<dd>Get the start state</dd>
<dt><a name="word8"><b>fsm-start!</b>	( fst fsm -- )</dt>
<dd>Set the start state</dd>
</dl>
<h4>State words</h4>
<dl>
<dt><a name="word9"><b>fsm-new-state</b>	( x xt1 xt2 c-addr1 u1 fsm -- fst )</dt>
<dd>Add a new state with label c-addr1 u1, entry action xt1, exit action xt2 and data x</dd>
<dt><a name="word10"><b>fsm-start</b>	( fsm -- )</dt>
<dd>Start the finite state machine</dd>
<dt><a name="word11"><b>fsm-find-state</b>	( c-addr u fsm -- fst | nil )</dt>
<dd>Find the state by its label c-addr u in the fsm</dd>
</dl>
<h4>Transition words</h4>
<dl>
<dt><a name="word12"><b>fsm-new-transition</b>	( x xt c-addr1 u1 fst1 fst2 fsm -- ftr )</dt>
<dd>Add a new transition from state fst1 to state fst2 with label c-addr1 u1, action xt and data x</dd>
<dt><a name="word13"><b>fsm-any-transition</b>	( x xt c-addr1 u1 fst1 fst2 fsm -- ftr )</dt>
<dd>Set the any transition for state fst1 to state fst2 with label c-addr1 u1, action xt and data x</dd>
</dl>
<h4>Event words</h4>
<dl>
<dt><a name="word14"><b>fsm-feed</b>	( n fsm -- fst | nil )</dt>
<dd>Feed the event to the current state, return the next state or nil if the event did not match any condition</dd>
<dt><a name="word15"><b>fsm-try</b>	( n fsm -- fst | nil )</dt>
<dd>Try the event for the current event, return the next state, but do not move to this state</dd>
</dl>
<h4>Conversion words</h4>
<dl>
<dt><a name="word16"><b>fsm-to-dot</b>	( c-addr u tos fsm -- )</dt>
<dd>Convert the fsm to a dot string using the stream, giving the graph the name c-addr u</dd>
</dl>
<h4>Inspection</h4>
<dl>
<dt><a name="word17"><b>fsm-dump</b>	( fsm -- )</dt>
<dd>Dump the fsm variable</dd>
</dl>
<h3>Examples</h3>
<pre>
include ffl/fsm.fs
include ffl/enm.fs


\ Example: vending machine


\ Enumerate the events

begin-enumeration
enum: voilence
enum: coin
enum: choice
enum: refuse
enum: #events
end-enumeration


\ Create the finite state machine on the heap with #events events

#events fsm-new value machine


\ Create the entry and exit action words

: say-thank-you  ( fst -- = Say 'thank you' after a coin or choice )
  drop
  ." Thank you" cr
;

: say-choice?    ( fst -- = Ask for choice after the coin )
  drop
  ." Please make your choice" cr
;

: say-coin?      ( fst -- = Ask for coin after the choice )
  drop
  ." Please enter your coin" cr
;

: call-support   ( fst -- = Call support after voilence, states data contains the phone number )
  ." Voilence against the machine, calling: " fst-data@ . cr
;


\ Create the states in the state machine

0     nil            ' say-thank-you s" start"    machine fsm-new-state value start
0   ' say-choice?    ' say-thank-you s" choice?"  machine fsm-new-state value choice?
0   ' say-coin?      ' say-thank-you s" coin?"    machine fsm-new-state value coin?
112 ' call-support     nil           s" support"  machine fsm-new-state value support


\ Set extra dot attributes for the support state

s" color=red" support fst-attributes!


\ Create the transitions for state start, use the bit array to set the condition

0     nil             s" coin"      start choice? machine fsm-new-transition ftr-condition@ coin     swap bar-set-bit
0     nil             s" choice"    start coin?   machine fsm-new-transition ftr-condition@ choice   swap bar-set-bit
0     nil             s" voilence"  start support machine fsm-new-transition ftr-condition@ voilence swap bar-set-bit

s" voilence" start fst-find-transition s" color=yellow" rot ftr-attributes!


\ Create the transition actions for choice? and coin? states

: deliver-choice   ( n ftr -- = Deliver the choosen product )
  2drop
  ." Deliver choice" cr
;

: do-refund        ( n ftr -- = Refused the product, refund the coin )
  2drop
  ." Refund coin" cr
;


\ Create the transitions for state choice?

0   ' deliver-choice  s" choice"    choice? start   machine fsm-new-transition ftr-condition@ choice   swap bar-set-bit
0   ' do-refund       s" refuse"    choice? start   machine fsm-new-transition ftr-condition@ refuse   swap bar-set-bit
0     nil             s" voilence"  choice? support machine fsm-new-transition ftr-condition@ voilence swap bar-set-bit


\ Set extra dot attributes for the voilence transition

s" voilence" choice? fst-find-transition s" color=yellow" rot ftr-attributes!


\ Create the transitions for state coin?

0   ' deliver-choice  s" coin"      coin? start   machine fsm-new-transition ftr-condition@ coin     swap bar-set-bit
0     nil             s" refuse"    coin? start   machine fsm-new-transition ftr-condition@ refuse   swap bar-set-bit
0     nil             s" voilence"  coin? support machine fsm-new-transition ftr-condition@ voilence swap bar-set-bit

s" voilence" coin? fst-find-transition s" color=yellow" rot ftr-attributes!


\ Start the state machine and feed it events 

machine fsm-start

coin     machine fsm-feed drop
choice   machine fsm-feed drop
coin     machine fsm-feed drop
refuse   machine fsm-feed drop
choice   machine fsm-feed drop
coin     machine fsm-feed drop
voilence machine fsm-feed drop


\ Create a text output stream for writing the state machine to dot

tos-new value dot-tos


\ Create the writer word

: write-dot    ( c-addr u file-id -- flag = Write the string )
  write-line 
  0=
;


\ Create the output file

s" out.dot" w/o create-file throw value dot-file


\ Set the writer word and the file in the stream

dot-file  ' write-dot  dot-tos  tos-set-writer


\ Write the state machine to the dot-file with graph name "Machine"

s" Machine" dot-tos machine fsm-to-dot


\ Free the dot stream

dot-tos tos-free


\ Close the dot file

dot-file close-file throw


\ To generate an image, use for example: dot -Tpng -o fsm.png out.dot

\ ==============================================================================
</pre>
<hr>
<div align="center">generated 24-Jul-2010 by <b>ofcfrth-0.10.0</b></div>
</body>
</html>
